﻿using FB.Helpers;
using FB.Providers.EmployeeInfo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace FB.Providers
{
    public class EmployeeInfoService
    {
        EmployeeInfoUnit _UOW;

        public EmployeeInfoUnit EmployeeInfoUnit { get { return _UOW; } }

        internal EmployeeInfoService(EmployeeInfoUnit unit)
        {
            _UOW = unit;
        }


        public int SaveChanges(bool AutoRefresh = false)
        {
            return _UOW.SaveChanges(AutoRefresh);
        }

        #region Employee Management


        public EmployeeType GetEmployeeType(string EMPType)
        {
            return _UOW.EmployeeTypeRepository.GetByKey(EMPType);
        }


        public IQueryable<EmployeeType> GetAllEmployeeTypes(bool IncludeDeleted = false)
        {
            var result = _UOW.EmployeeTypeRepository.Get();
            return !IncludeDeleted ? result.Where(w => w.RecordState == Enums.RecordState.Active) : result;
        }


        public string GenerateEMPCode(string EMPType)
        {
            var code = string.Empty;

            var employeeType = _UOW.EmployeeTypeRepository.GetByKey(EMPType);
            if (null != employeeType)
            {
                code = string.Format("{0}{1}", employeeType.EMPType, employeeType.Sequence.CurrentValue.ToString().PadLeft(6, '0'));
                employeeType.Sequence.CurrentValue = employeeType.Sequence.CurrentValue + 1;

                //_UOW.SequenceRepository.Update(employeeType.Sequence);
                //_UOW.SaveChanges(true);
            }

            return code;
        }

        public Employee GetEmployee(string EMPCode)
        {
            return _UOW.EmployeeRepository.GetByKey(EMPCode);
        }

        public Employee GetEmployeeByUserKey(Guid userid)
        {
            var query = _UOW.EmployeeRepository.Get(t => t.UserID == userid);
            return query.FirstOrDefault();
        }

        public Employee GetEmployeeByUserName(string username)
        {
            var query = _UOW.EmployeeRepository.Get(t => t.UserName == username.ToLower());
            return query.FirstOrDefault();
        }
        public IQueryable<EmployeeInPosition> GetEmployeePositionInfo(string EMPCode)
        {
            var query = _UOW.EmployeeInPositionRepository.Get(t => t.EMPCode == EMPCode);
            return query;
        }

        public IQueryable<EmployeeInPosition> GetAllEmployeePositionInfo()
        {
            var result = _UOW.EmployeeInPositionRepository.Get();
            return result;
        }

        public IQueryable<Employee> GetAllEmployees(bool IncludeDeleted = false, string includeProperties = "")
        {
            var result = FindEmployees(includeProperties: includeProperties);
            return (!IncludeDeleted) ? result.Where( w=>w.RecordState == Enums.RecordState.Active ) : result;
        }

        public IQueryable<Employee> FindEmployees(Expression<Func<Employee, bool>> filter = null, string includeProperties = "")
        {
            return _UOW.EmployeeRepository.Get(filter: filter, includeProperties: includeProperties);
        }

        public List<Employee> FindEmployees(
            Expression<Func<Employee, bool>> filter,
            Func<IQueryable<Employee>, IOrderedQueryable<Employee>> orderBy,
            int pageIndex, int pageSize, out int totalRecords, string includeProperties = "")
        {
            var result = _UOW.EmployeeRepository.Get(filter, orderBy: orderBy, includeProperties: includeProperties);
            totalRecords = result.Count();

            return result.Skip(pageSize * pageIndex).Take(pageSize).ToList();
        }

        public bool CreateEmployee(Employee employee)
        {
            var pw = AppSettingsBase.DefaultUserPwd;

            #region create user login
            
            
            //var m = membership.Create(employee.UserName, pw, string.Empty, string.Empty, string.Empty, true);
            var m = System.Web.Security.Membership.CreateUser(employee.UserName, pw);
            employee.UserID = (Guid)m.ProviderUserKey;
            var membership = new FB.Membership.AspNetMembershipProviderWrapper();
            membership.SetUserType(employee.UserID.Value, Membership.UserType.Employee);
            
            #endregion

            var EMPCode = GenerateEMPCode(employee.EMPType);
            employee.EMPCode = EMPCode;
            //employee.EmployeeType = 

            if (null != employee.PostDetails && employee.PostDetails.Count > 0)
            {
                foreach (var p in employee.PostDetails)
                {
                    p.EMPCode = EMPCode;
                }
            }

            _UOW.EmployeeRepository.Insert(employee);
            var result = SaveChanges() > 0;

            if (!result && m != null)
            {
                //rollback
                System.Web.Security.Membership.DeleteUser(m.UserName);
            }
            


            return result;
        }


        public bool UpdateEmployee(Employee modelToUpdate, bool UpdateSubordinates = false, bool UpdatePostDetails = false)
        {
            var result = false;
            var emp = _UOW.EmployeeRepository.GetByKey(modelToUpdate.EMPCode);
            if (null != emp)
            {
                emp.Status = modelToUpdate.Status;
                emp.RefCode = modelToUpdate.RefCode;
                emp.LastName = modelToUpdate.LastName;
                emp.FirstName = modelToUpdate.FirstName;
                emp.Alias = modelToUpdate.Alias;
                emp.ChineseName = modelToUpdate.ChineseName;
                emp.Gender = modelToUpdate.Gender;
                emp.Email = modelToUpdate.Email;
                emp.Mobile = modelToUpdate.Mobile;
                emp.TerminationDate = modelToUpdate.TerminationDate;
                emp.TerminationType = modelToUpdate.TerminationType;
                emp.ExtensionNo = modelToUpdate.ExtensionNo;

                #region subordinate

                if (UpdateSubordinates)
                {
                    // remove subordinate
                    if (null != emp.Subordinates)
                    {
                        var pendingRemoveSubordinates = (from e in emp.Subordinates
                                                         where null == modelToUpdate.Subordinates || !modelToUpdate.Subordinates.Contains(e)
                                                         select e).ToList();

                        pendingRemoveSubordinates.ForEach(e => emp.Subordinates.Remove(e));
                    }

                    // add subordinate
                    if (null != modelToUpdate.Subordinates)
                    {
                        foreach (var e in modelToUpdate.Subordinates)
                        {
                            if (!emp.Subordinates.Contains(e))
                                emp.Subordinates.Add(e);
                        }
                    }
                }

                #endregion

                _UOW.EmployeeRepository.Update(emp);


                
                #region position info

                if (UpdatePostDetails)
                {
                    // remove
                    if (null != emp.PostDetails)
                    {
                        var pendingDelPost = (from p in emp.PostDetails
                                              where modelToUpdate.PostDetails == null || !modelToUpdate.PostDetails.Select(s => s.ID).Contains(p.ID)
                                              select p).ToList();

                        pendingDelPost.ForEach(p => _UOW.EmployeeInPositionRepository.Delete(p));
                    }

                    // add or update 
                    if (null != modelToUpdate.PostDetails)
                    {
                        foreach (var p in modelToUpdate.PostDetails)
                        {
                            // create new
                            if (p.ID == 0)
                            {
                                //employee.PostDetails.Add(p);
                                _UOW.EmployeeInPositionRepository.Insert(p);
                            }
                            else
                            {
                                var post = emp.PostDetails.Where(w => w.ID == p.ID).FirstOrDefault();
                                if (null != post)
                                {
                                    post.COMCode = p.COMCode;
                                    post.DEPTCode = p.DEPTCode;
                                    post.TEAMCode = p.TEAMCode;
                                    post.POSCode = p.POSCode;
                                    post.CropTitle = p.CropTitle;
                                    post.IsPrimary = p.IsPrimary;

                                    _UOW.EmployeeInPositionRepository.Update(post);
                                }
                            }
                        }
                    }
                }

                #endregion
                

                result = SaveChanges() > 0;
            }



            
            return result;
        }


        public void DeleteEmployee(string EMPCode)
        {
            var emp = _UOW.EmployeeRepository.GetByKey(EMPCode);
            if (null != emp)
            {
                if (emp is FB.Data.Models.IRecordState)
                {
                    emp.RecordState = Enums.RecordState.Deleted;
                    _UOW.EmployeeRepository.Update(emp);
                }

                _UOW.SaveChanges();
            }
        }


        public bool TerminateEmployee(string EMPCode, DateTime? TerminationDate)
        {
            var result = false;
            var emp = _UOW.EmployeeRepository.GetByKey(EMPCode);
            if (null != emp)
            {
                emp.TerminationDate = TerminationDate;
                if (TerminationDate.HasValue)
                {
                    emp.Status = (emp.TerminationDate > DateTime.Today) ? Enums.EmployeeStatus.ToBeTerminated : Enums.EmployeeStatus.Terminated;
                }
                else
                    emp.Status = Enums.EmployeeStatus.Normal;


                _UOW.EmployeeRepository.Update(emp);

                result = SaveChanges() > 0;
            }

            return result;
        }


        public byte[] GetEmployeePhoto(string EMPCode)
        {
            var result = _UOW.ProfilePicRepository.GetByKey(EMPCode);
            if (result != null)
            {
                return result.ProfileImage ?? null;
            }
            return null;
        }


        public EmployeeInPosition GetEmployeePositionInfoByKey(int ID)
        {
            return _UOW.EmployeeInPositionRepository.GetByKey(ID);
        }


        public bool AddEmployeePositionInfo(EmployeeInPosition PositionInfo)
        {
            if (PositionInfo.IsPrimary)
                RestPrimaryPosition(PositionInfo.EMPCode);

            _UOW.EmployeeInPositionRepository.Insert(PositionInfo);

            return SaveChanges() > 0;
        }

        public bool UpdateEmployeePositionInfo(EmployeeInPosition PositionInfo)
        {
            if (PositionInfo.IsPrimary)
                RestPrimaryPosition(PositionInfo.EMPCode);

            _UOW.EmployeeInPositionRepository.Update(PositionInfo);

            return SaveChanges() > 0;
        }

        public bool RemoveEmployeePositionInfo(EmployeeInPosition PositionInfo)
        {
            _UOW.EmployeeInPositionRepository.Delete(PositionInfo);
            return SaveChanges() > 0;
        }


        void RestPrimaryPosition(string EMPCode)
        {
            var result = _UOW.EmployeeInPositionRepository.Get(w => w.EMPCode == EMPCode && w.IsPrimary);
            if (result.Count() > 0)
            {
                foreach (var ep in result)
                    ep.IsPrimary = false;
            }
        }

        #endregion


        #region Company Management

        public bool CreateCompany(Company company)
        {
            _UOW.CompanyRepository.Insert(company);
            var result = SaveChanges() > 0;
            return result;
        }


        public bool UpdateCompany(Company company)
        {
            var c = _UOW.CompanyRepository.GetByKey(company.COMCode);

            c.COMCode = company.COMCode;
            c.Name = company.Name;
            c.ParentCOMCode = company.ParentCOMCode;
            c.Order = company.Order;

            _UOW.CompanyRepository.Update(c);
            var result = SaveChanges() > 0;
            return result;
        }

        public IQueryable<Company> GetAllCompanies(bool IncludeDeleted = false)
        {
            var result = FindCompanies();
            return (!IncludeDeleted) ? result.Where(w => w.RecordState == Enums.RecordState.Active) : result;
        }

        public IQueryable<Company> FindCompanies(Expression<Func<Company, bool>> filter = null)
        {
            return _UOW.CompanyRepository.Get(filter: filter);
        }

        #endregion


        #region Department Management

        public bool CreateDepartment(Department department)
        {
            _UOW.DepartmentRepository.Insert(department);
            var result = SaveChanges() > 0;
            return result;
        }


        public bool UpdateDepartment(Department department)
        {
            var d = _UOW.DepartmentRepository.GetByKey(department.DEPTCode);

            d.Name = department.Name;
            d.COMCode = department.COMCode;
            d.Order = department.Order;
            d.ParentDEPTCode = department.ParentDEPTCode;

            _UOW.DepartmentRepository.Update(d);
            var result = SaveChanges() > 0;
            return result;
        }


        public Department GetDepartment(string DEPTCode)
        {
            return _UOW.DepartmentRepository.GetByKey(DEPTCode);
        } 

        public IQueryable<Department> GetDepartmentByCompany(string COMCode, bool IncludeDeleted = false)
        {
            var result = FindDepartments(w => w.COMCode.ToUpper() == COMCode.ToUpper());
            return (!IncludeDeleted) ? result.Where(w => w.RecordState == Enums.RecordState.Active) : result;
        }

        public IQueryable<Department> GetAllDepartments(bool IncludeDeleted = false)
        {
            var result = FindDepartments();
            return (!IncludeDeleted) ? result.Where(w => w.RecordState == Enums.RecordState.Active) : result;
        }

        public IQueryable<Department> FindDepartments(Expression<Func<Department, bool>> filter = null)
        {
            return _UOW.DepartmentRepository.Get(filter: filter);
        }

        public IQueryable<DepartmentGroup> GetDepartmentGroup(string[] DeptCode = null)
        {
            var Groups = _UOW.Repository<DepartmentGroup>().Get();
            if (DeptCode != null)
            {
                var MasterDeptCodes = _UOW.Repository<Department>().Get().Where(w => DeptCode.Contains(w.DEPTCode)).Select(s => s.MasterDeptCode).ToList();

                Groups = from dg in Groups
                         where
                         MasterDeptCodes.Contains(dg.DeptGroupID)
                         select dg;
            }
            return Groups;
        }

        #endregion


        #region Team Management

        public Team GetTeam(string TEAMCode)
        {
            return _UOW.TeamRepository.GetByKey(TEAMCode);
        } 

        public IQueryable<Team> GetTeamByDepartment(string DEPTCode, bool IncludeDeleted = false)
        {
            var result = FindTeams(w => w.DEPTCode.ToUpper() == DEPTCode.ToUpper());
            return (!IncludeDeleted) ? result.Where(w => w.RecordState == Enums.RecordState.Active) : result;
        }

        public IQueryable<Team> GetAllTeams(bool IncludeDeleted = false)
        {
            var result = FindTeams();
            return (!IncludeDeleted) ? result.Where(w => w.RecordState == Enums.RecordState.Active) : result;
        }

        public IQueryable<Team> FindTeams(Expression<Func<Team, bool>> filter = null)
        {
            return _UOW.TeamRepository.Get(filter: filter);
        }

        #endregion



        #region Position Management

        public bool CreatePosition(Position position)
        {
            _UOW.PositionRepository.Insert(position);
            var result = SaveChanges() > 0;
            return result;
        }


        public bool UpdatePosition(Position position)
        {
            var p = _UOW.PositionRepository.GetByKey(position.POSCode);

            p.Name = position.Name;
            p.Grading = position.Grading;
            p.Order = position.Order;


            _UOW.PositionRepository.Update(p);
            var result = SaveChanges() > 0;
            return result;
        }


        public Position GetPosition(string POSCode)
        {
            return _UOW.PositionRepository.GetByKey(POSCode);
        }

        public IQueryable<Position> GetAllPositions(bool IncludeDeleted = false)
        {
            var result = FindPositions();
            return (!IncludeDeleted) ? result.Where(w => w.RecordState == Enums.RecordState.Active) : result;
        }

        public IQueryable<Position> FindPositions(Expression<Func<Position, bool>> filter = null)
        {
            return _UOW.PositionRepository.Get(filter: filter);
        }

        #endregion


        public int UpdateEmployeeImage(string fileName,Employee employee)
        {
         //   _UOW.ProfilePicRepository
            return 1;
        }

        public bool CreateEmployeePhoto(string EMPCode, byte[] EmployeePhoto)
        {
            ProfilePic NewFile = new ProfilePic();
            NewFile.EMPCode = EMPCode;
            NewFile.ProfileImage = EmployeePhoto;
            _UOW.ProfilePicRepository.Insert(NewFile);
          bool result= _UOW.ProfilePicRepository.SaveChanges() >0;
          return result;
        }

        public bool UpdateEmployeePhoto(string EMPCode, byte[] EmployeePhoto)
        {
            ProfilePic UpdateFile = _UOW.ProfilePicRepository.GetByKey(EMPCode);
            if (UpdateFile == null)  // 如果为空 说明创建的时候没有添加图片
            {
                CreateEmployeePhoto( EMPCode, EmployeePhoto);
                return false;
            }
            UpdateFile.ProfileImage = EmployeePhoto;
            _UOW.ProfilePicRepository.Update(UpdateFile);
            var result = SaveChanges() > 0;
            return result;
        }

    }
}
